home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 10
/
AACD 10.iso
/
AACD
/
Games
/
MAME
/
src
/
cpu
/
m6502
/
ops02.h
< prev
next >
Wrap
C/C++ Source or Header
|
2000-05-08
|
25KB
|
744 lines
/*****************************************************************************
*
* ops02.h
* Addressing mode and opcode macros for 6502,65c02,65sc02,6510,n2a03 CPUs
*
* Copyright (c) 1998,1999,2000 Juergen Buchmueller, all rights reserved.
* 65sc02 core Copyright (c) 2000 Peter Trauner, all rights reserved.
*
* - This source code is released as freeware for non-commercial purposes.
* - You are free to use and redistribute this code in modified or
* unmodified form, provided you list me in the credits.
* - If you modify this source code, you must add a notice to each modified
* source file that it has been changed. If you're a nice person, you
* will clearly mark each change too. :)
* - If you wish to use this for commercial purposes, please contact me at
* pullmoll@t-online.de
* - The author of this copywritten work reserves the right to change the
* terms of its usage and license at any time, including retroactively
* - This entire notice must remain in the source code.
*
*****************************************************************************/
/* 6502 flags */
#define F_C 0x01
#define F_Z 0x02
#define F_I 0x04
#define F_D 0x08
#define F_B 0x10
#define F_T 0x20
#define F_V 0x40
#define F_N 0x80
/* some shortcuts for improved readability */
#define A m6502.a
#define X m6502.x
#define Y m6502.y
#define P m6502.p
#define S m6502.sp.b.l
#define SPD m6502.sp.d
#define NZ m6502.nz
#define SET_NZ(n) \
if ((n) == 0) P = (P & ~F_N) | F_Z; else P = (P & ~(F_N | F_Z)) | ((n) & F_N)
#define SET_Z(n) \
if ((n) == 0) P |= F_Z; else P &= ~F_Z
#define EAL m6502.ea.b.l
#define EAH m6502.ea.b.h
#define EAW m6502.ea.w.l
#define EAD m6502.ea.d
#define ZPL m6502.zp.b.l
#define ZPH m6502.zp.b.h
#define ZPW m6502.zp.w.l
#define ZPD m6502.zp.d
#define PCL m6502.pc.b.l
#define PCH m6502.pc.b.h
#define PCW m6502.pc.w.l
#define PCD m6502.pc.d
#define PPC m6502.ppc.d
#if FAST_MEMORY
extern MHELE *cur_mwhard;
extern MHELE *cur_mrhard;
extern UINT8 *RAM;
#endif
#define CHANGE_PC change_pc16(PCD)
/***************************************************************
* RDOP read an opcode
***************************************************************/
#define RDOP() cpu_readop(PCW++)
/***************************************************************
* RDOPARG read an opcode argument
***************************************************************/
#define RDOPARG() cpu_readop_arg(PCW++)
/***************************************************************
* RDMEM read memory
***************************************************************/
#if FAST_MEMORY
#define RDMEM(addr) \
((cur_mrhard[(addr) >> (ABITS2_16 + ABITS_MIN_16)]) ? \
cpu_readmem16(addr) : RAM[addr])
#else
#define RDMEM(addr) cpu_readmem16(addr)
#endif
/***************************************************************
* WRMEM write memory
***************************************************************/
#if FAST_MEMORY
#define WRMEM(addr,data) \
if (cur_mwhard[(addr) >> (ABITS2_16 + ABITS_MIN_16)]) \
cpu_writemem16(addr,data); \
else \
RAM[addr] = data
#else
#define WRMEM(addr,data) cpu_writemem16(addr,data)
#endif
/***************************************************************
* BRA branch relative
* extra cycle if page boundary is crossed
***************************************************************/
#define BRA(cond) \
if (cond) \
{ \
tmp = RDOPARG(); \
EAW = PCW + (signed char)tmp; \
m6502_ICount -= (PCH == EAH) ? 3 : 4; \
PCD = EAD; \
CHANGE_PC; \
} \
else \
{ \
PCW++; \
m6502_ICount -= 2; \
}
/***************************************************************
*
* Helper macros to build the effective address
*
***************************************************************/
/***************************************************************
* EA = zero page address
***************************************************************/
#define EA_ZPG \
ZPL = RDOPARG(); \
EAD = ZPD
/***************************************************************
* EA = zero page address + X
***************************************************************/
#define EA_ZPX \
ZPL = RDOPARG() + X; \
EAD = ZPD
/***************************************************************
* EA = zero page address + Y
***************************************************************/
#define EA_ZPY \
ZPL = RDOPARG() + Y; \
EAD = ZPD
/***************************************************************
* EA = absolute address
***************************************************************/
#define EA_ABS \
EAL = RDOPARG(); \
EAH = RDOPARG()
/***************************************************************
* EA = absolute address + X
***************************************************************/
#define EA_ABX \
EA_ABS; \
EAW += X
/***************************************************************
* EA = absolute address + Y
***************************************************************/
#define EA_ABY \
EA_ABS; \
EAW += Y
/***************************************************************
* EA = zero page + X indirect (pre indexed)
***************************************************************/
#define EA_IDX \
ZPL = RDOPARG() + X; \
EAL = RDMEM(ZPD); \
ZPL++; \
EAH = RDMEM(ZPD)
/***************************************************************
* EA = zero page indirect + Y (post indexed)
* subtract 1 cycle if page boundary is crossed
***************************************************************/
#define EA_IDY \
ZPL = RDOPARG(); \
EAL = RDMEM(ZPD); \
ZPL++; \
EAH = RDMEM(ZPD); \
if (EAL + Y > 0xff) \
m6502_ICount--; \
EAW += Y
/***************************************************************
* EA = indirect (only used by JMP)
***************************************************************/
#define EA_IND \
EA_ABS; \
tmp = RDMEM(EAD); \
EAL++; /* booby trap: stay in same page! ;-) */ \
EAH = RDMEM(EAD); \
EAL = tmp
/* read a value into tmp */
#define RD_IMM tmp = RDOPARG()
#define RD_ACC tmp = A
#define RD_ZPG EA_ZPG; tmp = RDMEM(EAD)
#define RD_ZPX EA_ZPX; tmp = RDMEM(EAD)
#define RD_ZPY EA_ZPY; tmp = RDMEM(EAD)
#define RD_ABS EA_ABS; tmp = RDMEM(EAD)
#define RD_ABX EA_ABX; tmp = RDMEM(EAD)
#define RD_ABY EA_ABY; tmp = RDMEM(EAD)
#define RD_ZPI EA_ZPI; tmp = RDMEM(EAD)
#define RD_IDX EA_IDX; tmp = RDMEM(EAD)
#define RD_IDY EA_IDY; tmp = RDMEM(EAD)
/* write a value from tmp */
#define WR_ZPG EA_ZPG; WRMEM(EAD, tmp)
#define WR_ZPX EA_ZPX; WRMEM(EAD, tmp)
#define WR_ZPY EA_ZPY; WRMEM(EAD, tmp)
#define WR_ABS EA_ABS; WRMEM(EAD, tmp)
#define WR_ABX EA_ABX; WRMEM(EAD, tmp)
#define WR_ABY EA_ABY; WRMEM(EAD, tmp)
#define WR_ZPI EA_ZPI; WRMEM(EAD, tmp)
#define WR_IDX EA_IDX; WRMEM(EAD, tmp)
#define WR_IDY EA_IDY; WRMEM(EAD, tmp)
/* write back a value from tmp to the last EA */
#define WB_ACC A = (UINT8)tmp;
#define WB_EA WRMEM(EAD, tmp)
/***************************************************************
***************************************************************
* Macros to emulate the plain 6502 opcodes
***************************************************************
***************************************************************/
/***************************************************************
* push a register onto the stack
***************************************************************/
#define PUSH(Rg) WRMEM(SPD, Rg); S--
/***************************************************************
* pull a register from the stack
***************************************************************/
#define PULL(Rg) S++; Rg = RDMEM(SPD)
/* 6502 ********************************************************
* ADC Add with carry
***************************************************************/
#define ADC \
if (P & F_D) \
{ \
int c = (P & F_C); \
int lo = (A & 0x0f) + (tmp & 0x0f) + c; \
int hi = (A & 0xf0) + (tmp & 0xf0); \
P &= ~(F_V | F_C|F_N|F_Z); \
if (!((lo+hi)&0xff)) P|=F_Z; \
if (lo > 0x09) \
{ \
hi += 0x10; \
lo += 0x06; \
} \
if (hi&0x80) P|=F_N; \
if (~(A^tmp) & (A^hi) & F_N) \
P |= F_V; \
if (hi > 0x90) \
hi += 0x60; \
if (hi & 0xff00) \
P |= F_C; \
A = (lo & 0x0f) + (hi & 0xf0); \
} \
else \
{ \
int c = (P & F_C); \
int sum = A + tmp + c; \
P &= ~(F_V | F_C); \
if (~(A^tmp) & (A^sum) & F_N) \
P |= F_V; \
if (sum & 0xff00) \
P |= F_C; \
A = (UINT8) sum; \
SET_NZ(A); \
}
/* 6502 ********************************************************
* AND Logical and
***************************************************************/
#define AND \
A = (UINT8)(A & tmp); \
SET_NZ(A)
/* 6502 ********************************************************
* ASL Arithmetic shift left
***************************************************************/
#define ASL \
P = (P & ~F_C) | ((tmp >> 7) & F_C); \
tmp = (UINT8)(tmp << 1); \
SET_NZ(tmp)
/* 6502 ********************************************************
* BCC Branch if carry clear
***************************************************************/
#define BCC BRA(!(P & F_C))
/* 6502 ********************************************************
* BCS Branch if carry set
***************************************************************/
#define BCS BRA(P & F_C)
/* 6502 ********************************************************
* BEQ Branch if equal
***************************************************************/
#define BEQ BRA(P & F_Z)
/* 6502 ********************************************************
* BIT Bit test
***************************************************************/
#define BIT \
P &= ~(F_N|F_V|F_Z); \
P |= tmp & (F_N|F_V); \
if ((tmp & A) == 0) \
P |= F_Z
/* 6502 ********************************************************
* BMI Branch if minus
***************************************************************/
#define BMI BRA(P & F_N)
/* 6502 ********************************************************
* BNE Branch if not equal
***************************************************************/
#define BNE BRA(!(P & F_Z))
/* 6502 ********************************************************
* BPL Branch if plus
***************************************************************/
#define BPL BRA(!(P & F_N))
/* 6502 ********************************************************
* BRK Break
* increment PC, push PC hi, PC lo, flags (with B bit set),
* set I flag, jump via IRQ vector
***************************************************************/
#define BRK \
PCW++; \
PUSH(PCH); \
PUSH(PCL); \
PUSH(P | F_B); \
P = (P | F_I); \
PCL = RDMEM(M6502_IRQ_VEC); \
PCH = RDMEM(M6502_IRQ_VEC+1); \
CHANGE_PC
/* 6502 ********************************************************
* BVC Branch if overflow clear
***************************************************************/
#define BVC BRA(!(P & F_V))
/* 6502 ********************************************************
* BVS Branch if overflow set
***************************************************************/
#define BVS BRA(P & F_V)
/* 6502 ********************************************************
* CLC Clear carry flag
***************************************************************/
#define CLC \
P &= ~F_C
/* 6502 ********************************************************
* CLD Clear decimal flag
***************************************************************/
#define CLD \
P &= ~F_D
/* 6502 ********************************************************
* CLI Clear interrupt flag
***************************************************************/
#define CLI \
if ((m6502.irq_state != CLEAR_LINE) && (P & F_I)) { \
logerror("M6502#%d CLI sets after_cli\n",cpu_getactivecpu()); \
m6502.after_cli = 1; \
} \
P &= ~F_I
/* 6502 ********************************************************
* CLV Clear overflow flag
***************************************************************/
#define CLV \
P &= ~F_V
/* 6502 ********************************************************
* CMP Compare accumulator
***************************************************************/
#define CMP \
P &= ~F_C; \
if (A >= tmp) \
P |= F_C; \
SET_NZ((UINT8)(A - tmp))
/* 6502 ********************************************************
* CPX Compare index X
***************************************************************/
#define CPX \
P &= ~F_C; \
if (X >= tmp) \
P |= F_C; \
SET_NZ((UINT8)(X - tmp))
/* 6502 ********************************************************
* CPY Compare index Y
***************************************************************/
#define CPY \
P &= ~F_C; \
if (Y >= tmp) \
P |= F_C; \
SET_NZ((UINT8)(Y - tmp))
/* 6502 ********************************************************
* DEC Decrement memory
***************************************************************/
#define DEC \
tmp = (UINT8)--tmp; \
SET_NZ(tmp)
/* 6502 ********************************************************
* DEX Decrement index X
***************************************************************/
#define DEX \
X = (UINT8)--X; \
SET_NZ(X)
/* 6502 ********************************************************
* DEY Decrement index Y
***************************************************************/
#define DEY \
Y = (UINT8)--Y; \
SET_NZ(Y)
/* 6502 ********************************************************
* EOR Logical exclusive or
***************************************************************/
#define EOR \
A = (UINT8)(A ^ tmp); \
SET_NZ(A)
/* 6502 ********************************************************
* ILL Illegal opcode
***************************************************************/
#define ILL \
logerror("M6502 illegal opcode %04x: %02x\n",(PCW-1)&0xffff, cpu_readop((PCW-1)&0xffff))
/* 6502 ********************************************************
* INC Increment memory
***************************************************************/
#define INC \
tmp = (UINT8)++tmp; \
SET_NZ(tmp)
/* 6502 ********************************************************
* INX Increment index X
***************************************************************/
#define INX \
X = (UINT8)++X; \
SET_NZ(X)
/* 6502 ********************************************************
* INY Increment index Y
***************************************************************/
#define INY \
Y = (UINT8)++Y; \
SET_NZ(Y)
/* 6502 ********************************************************
* JMP Jump to address
* set PC to the effective address
***************************************************************/
#define JMP \
if( EAD == PPC && !m6502.pending_irq && !m6502.after_cli ) \
if( m6502_ICount > 0 ) m6502_ICount = 0; \
PCD = EAD; \
CHANGE_PC
/* 6502 ********************************************************
* JSR Jump to subroutine
* decrement PC (sic!) push PC hi, push PC lo and set
* PC to the effective address
***************************************************************/
#define JSR \
EAL = RDOPARG(); \
PUSH(PCH); \
PUSH(PCL); \
EAH = RDOPARG(); \
PCD = EAD; \
CHANGE_PC
/* 6502 ********************************************************
* LDA Load accumulator
***************************************************************/
#define LDA \
A = (UINT8)tmp; \
SET_NZ(A)
/* 6502 ********************************************************
* LDX Load index X
***************************************************************/
#define LDX \
X = (UINT8)tmp; \
SET_NZ(X)
/* 6502 ********************************************************
* LDY Load index Y
***************************************************************/
#define LDY \
Y = (UINT8)tmp; \
SET_NZ(Y)
/* 6502 ********************************************************
* LSR Logic shift right
* 0 -> [7][6][5][4][3][2][1][0] -> C
***************************************************************/
#define LSR \
P = (P & ~F_C) | (tmp & F_C); \
tmp = (UINT8)tmp >> 1; \
SET_NZ(tmp)
/* 6502 ********************************************************
* NOP No operation
***************************************************************/
#define NOP
/* 6502 ********************************************************
* ORA Logical inclusive or
***************************************************************/
#define ORA \
A = (UINT8)(A | tmp); \
SET_NZ(A)
/* 6502 ********************************************************
* PHA Push accumulator
***************************************************************/
#define PHA \
PUSH(A)
/* 6502 ********************************************************
* PHP Push processor status (flags)
***************************************************************/
#define PHP \
PUSH(P)
/* 6502 ********************************************************
* PLA Pull accumulator
***************************************************************/
#define PLA \
PULL(A); \
SET_NZ(A)
/* 6502 ********************************************************
* PLP Pull processor status (flags)
***************************************************************/
#define PLP \
if ( P & F_I ) { \
PULL(P); \
if ((m6502.irq_state != CLEAR_LINE) && !(P & F_I)) { \
LOG(("M6502#%d PLP sets after_cli\n",cpu_getactivecpu())); \
m6502.after_cli = 1; \
} \
} else { \
PULL(P); \
} \
P |= (F_T|F_B);
/* 6502 ********************************************************
* ROL Rotate left
* new C <- [7][6][5][4][3][2][1][0] <- C
***************************************************************/
#define ROL \
tmp = (tmp << 1) | (P & F_C); \
P = (P & ~F_C) | ((tmp >> 8) & F_C); \
tmp = (UINT8)tmp; \
SET_NZ(tmp)
/* 6502 ********************************************************
* ROR Rotate right
* C -> [7][6][5][4][3][2][1][0] -> new C
***************************************************************/
#define ROR \
tmp |= (P & F_C) << 8; \
P = (P & ~F_C) | (tmp & F_C); \
tmp = (UINT8)(tmp >> 1); \
SET_NZ(tmp)
/* 6502 ********************************************************
* RTI Return from interrupt
* pull flags, pull PC lo, pull PC hi and increment PC
* PCW++;
***************************************************************/
#define RTI \
PULL(P); \
PULL(PCL); \
PULL(PCH); \
P |= F_T | F_B; \
if( (m6502.irq_state != CLEAR_LINE) && !(P & F_I) ) \
{ \
LOG(("M6502#%d RTI sets after_cli\n",cpu_getactivecpu())); \
m6502.after_cli = 1; \
} \
CHANGE_PC
/* 6502 ********************************************************
* RTS Return from subroutine
* pull PC lo, PC hi and increment PC
***************************************************************/
#define RTS \
PULL(PCL); \
PULL(PCH); \
PCW++; \
CHANGE_PC
/* 6502 ********************************************************
* SBC Subtract with carry
***************************************************************/
#define SBC \
if (P & F_D) \
{ \
int c = (P & F_C) ^ F_C; \
int sum = A - tmp - c; \
int lo = (A & 0x0f) - (tmp & 0x0f) - c; \
int hi = (A & 0xf0) - (tmp & 0xf0); \
if (lo & 0x10) \
{ \
lo -= 6; \
hi--; \
} \
P &= ~(F_V | F_C|F_Z|F_N); \
if( (A^tmp) & (A^sum) & F_N ) \
P |= F_V; \
if( hi & 0x0100 ) \
hi -= 0x60; \
if( (sum & 0xff00) == 0 ) \
P |= F_C; \
if( !((A-tmp-c) & 0xff) ) \
P |= F_Z; \
if( (A-tmp-c) & 0x80 ) \
P |= F_N; \
A = (lo & 0x0f) | (hi & 0xf0); \
} \
else \
{ \
int c = (P & F_C) ^ F_C; \
int sum = A - tmp - c; \
P &= ~(F_V | F_C); \
if( (A^tmp) & (A^sum) & F_N ) \
P |= F_V; \
if( (sum & 0xff00) == 0 ) \
P |= F_C; \
A = (UINT8) sum; \
SET_NZ(A); \
}
/* 6502 ********************************************************
* SEC Set carry flag
***************************************************************/
#define SEC \
P |= F_C
/* 6502 ********************************************************
* SED Set decimal flag
***************************************************************/
#define SED \
P |= F_D
/* 6502 ********************************************************
* SEI Set interrupt flag
***************************************************************/
#define SEI \
P |= F_I
/* 6502 ********************************************************
* STA Store accumulator
***************************************************************/
#define STA \
tmp = A
/* 6502 ********************************************************
* STX Store index X
***************************************************************/
#define STX \
tmp = X
/* 6502 ********************************************************
* STY Store index Y
***************************************************************/
#define STY \
tmp = Y
/* 6502 ********************************************************
* TAX Transfer accumulator to index X
***************************************************************/
#define TAX \
X = A; \
SET_NZ(X)
/* 6502 ********************************************************
* TAY Transfer accumulator to index Y
***************************************************************/
#define TAY \
Y = A; \
SET_NZ(Y)
/* 6502 ********************************************************
* TSX Transfer stack LSB to index X
***************************************************************/
#define TSX \
X = S; \
SET_NZ(X)
/* 6502 ********************************************************
* TXA Transfer index X to accumulator
***************************************************************/
#define TXA \
A = X; \
SET_NZ(A)
/* 6502 ********************************************************
* TXS Transfer index X to stack LSB
* no flags changed (sic!)
***************************************************************/
#define TXS \
S = X
/* 6502 ********************************************************
* TYA Transfer index Y to accumulator
***************************************************************/
#define TYA \
A = Y; \
SET_NZ(A)